#include <audio/MIDI/MIDINoteTrack.h>

namespace ne
{
    MIDINoteTrack::MIDINoteTrack(const std::string &name)
        : mName(name),
          mChannel(MIDI_CHANNEL0),
          mInstrument(MIDI_ACOUSTICGRANDPIANO)
    {
    }

    bool MIDINoteTrack::build(MIDITrack *pTrack)
    {
        destroyAllNotes();

        if (!pTrack) return false;

        setName(pTrack->getName());
        setChannel(pTrack->getChannel());
        setInstrument(pTrack->getInstrument());

        for (MIDIEventListIterator it=pTrack->begin(); it!=pTrack->end(); ++it)
        {
            MIDIChannelEvent *pChannelEvent = dynamic_cast<MIDIChannelEvent*>(*it);
            if (pChannelEvent)
            {
                if (pChannelEvent->getType() == MIDI_NOTE_ON &&
                    pChannelEvent->parameter2 > 0)
                {
                    MIDINote *pNote = new MIDINote();
                    pNote->channel = pChannelEvent->channel;
                    pNote->pitch = pChannelEvent->parameter1;
                    pNote->velocity = pChannelEvent->parameter2;
                    pNote->releaseVelocity = 0;
                    pNote->absoluteTicks = pChannelEvent->absoluteTicks;
                    pNote->duration = 0;

                    MIDIEventListIterator itOff = it;
                    ++itOff;
                    while (itOff != pTrack->end())
                    {
                        MIDIChannelEvent *pEvent = dynamic_cast<MIDIChannelEvent*>(*itOff);
                        if (pEvent && pEvent->parameter1 == pNote->pitch)
                        {
                            if ((pEvent->getType() == MIDI_NOTE_ON && pEvent->parameter2 == 0) ||
                                (pEvent->getType() == MIDI_NOTE_OFF))
                            {
                                pNote->releaseVelocity = pEvent->parameter2;
                                pNote->duration = pEvent->absoluteTicks - pNote->absoluteTicks;
                                break;
                            }
                        }
                        ++itOff;
                    }

                    mNoteList.push_back(pNote);
                }
            }
        }

        return true;
    }

    void MIDINoteTrack::destroyAllNotes()
    {
        for (ne::MIDINoteListIterator it=mNoteList.begin(); it!=mNoteList.end(); ++it)
        {
            delete (*it);
        }
        mNoteList.clear();
    }

    MIDINoteTrack::~MIDINoteTrack()
    {
        destroyAllNotes();
    }
}
